package cn.icanci.ladybird.service.user.impl;

import cn.icanci.ladybird.common.result.JsonData;
import cn.icanci.ladybird.common.util.cache.RedisUtils;
import cn.icanci.ladybird.common.util.task.DelayQueueManager;
import cn.icanci.ladybird.common.util.task.DelayTask;
import cn.icanci.ladybird.common.util.task.TaskBase;
import cn.icanci.ladybird.pojo.dto.UserBuyerTicketDTO;
import cn.icanci.ladybird.pojo.entity.*;
import cn.icanci.ladybird.service.*;
import cn.icanci.ladybird.service.user.UserBuyerTicketService;
import cn.icanci.ladybird.service.user.UserConfirmOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author: icanci
 * @date: Created in 2020/10/10 16:35
 * @classAction: 处理用户的座位信息
 */
@Slf4j
@Service
public class UserConfirmOrderServiceImpl implements UserConfirmOrderService {

    @Autowired
    private TicketSeatService ticketSeatService;
    @Autowired
    private OrderInfoService orderInfoService;
    @Autowired
    private TicketDetailsService ticketDetailsService;
    @Autowired
    private UserInfoOrderInfoMiddleService userInfoOrderInfoMiddleService;
    @Autowired
    private UserBuyerTicketService userBuyerTicketService;
    @Autowired
    private OrderInfoTicketInfoMiddleService orderInfoTicketInfoMiddleService;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private DelayQueueManager delayQueueManager;
    /**
     * 锁
     */
    private final Lock lock = new ReentrantLock();

    @Transactional(rollbackFor = Exception.class)
    @Override
    public JsonData confirmOrder(String[] list, Long detailsId, String cityAndVenue, HttpServletRequest request) {
        try {
            // 处理座位的信息
            // 因为是多个票进行操作，所以只要有一个票被锁定，整个订单都被锁
            // 求其实座位只需要处理
            ArrayList<TicketSeat> ticketSeatList = new ArrayList<>();
            ArrayList<Long> seatsList = new ArrayList<>();
            for (String s : list) {
                // 第零个是 id
                // 第一个是 x
                // 第二个是 y
                // 第三个是价格
                String[] split = s.split("-");
                TicketSeat ticketSeat = ticketSeatService.queryById(Long.valueOf(split[0]));
                // 判断票是否存在
                if (null == ticketSeat) {
                    return JsonData.builderError("操作失败，票已经售出！");
                }
                // 判断座位的可用状态 是否可用，和座位的状态
                if (ticketSeat.getTicketEnable().equals(0)) {
                    return JsonData.builderError("操作失败，票不可用！");
                }
                // 判断座位的出售状态
                if (ticketSeat.getTicketState().equals(0)) {
                    return JsonData.builderError("操作失败，票已经售出！");
                }
                if (ticketSeat.getTicketState().equals(1)) {
                    return JsonData.builderError("操作失败，票已经被其他人锁定！");
                }
                // 判断页面传递的票的 x坐标、y坐标、价格 是否和数据库的一致
                // 如果一致
                System.err.println(ticketSeat.getTicketX() + " --- " + split[1]);
                System.err.println(ticketSeat.getTicketY() + " --- " + split[2]);
                System.err.println(ticketSeat.getTicketPrice() + " --- " + split[3]);
                if (!(ticketSeat.getTicketX().equals(Integer.valueOf(split[1]))
                        && ticketSeat.getTicketY().equals(Integer.valueOf(split[2]))
                        && ticketSeat.getTicketPrice().equals(Double.valueOf(split[3])))) {
                    return JsonData.builderError("操作失败，票信息有误！");
                }
                // 验证通过
                ticketSeatList.add(ticketSeat);
                seatsList.add(ticketSeat.getTicketSeatId());
            }
            // 全部验证通过 更新票的状态

            // 返回给界面的信息集合
            ArrayList<Object> returnData = new ArrayList<>();

            synchronized (UserConfirmOrderServiceImpl.class) {
                double price = 0d;
                StringBuilder builder = new StringBuilder(60);
                StringBuilder seatsId = new StringBuilder(40);
                for (int i = 0; i < ticketSeatList.size(); i++) {
                    TicketSeat ticketSeat = ticketSeatList.get(i);
                    ticketSeat.setTicketState(1);
                    ticketSeat.setUpdateTime(new Date());
                    // 更新座位
                    ticketSeatService.update(ticketSeat);
                    // 计算价格
                    price += Double.parseDouble(ticketSeat.getTicketPrice().toString());
                    // 计算座位
                    if (i != ticketSeatList.size() - 1) {
                        builder.append(ticketSeat.getTicketX())
                                .append("排")
                                .append(ticketSeat.getTicketY())
                                .append("座,");
                        seatsId.append(ticketSeat.getTicketSeatId()).append(",");
                    } else {
                        builder.append(ticketSeat.getTicketX())
                                .append("排")
                                .append(ticketSeat.getTicketY())
                                .append("座");
                        seatsId.append(ticketSeat.getTicketSeatId());
                    }
                }
                // 查询票的信息
                TicketDetails ticketDetails = ticketDetailsService.queryById(detailsId);
                // 根据票生成订单
                OrderInfo orderInfo = new OrderInfo();
                // 商品id
                orderInfo.setOrderInfoTicketDetailsId(detailsId);
                // 订单总价
                orderInfo.setOrderInfoTotalPrice(price);
                // 订单生成的时间、创建时间、更新时间
                orderInfo.setOrderInfoTime(new Date());
                orderInfo.setCreateTime(new Date());
                orderInfo.setUpdateTime(new Date());
                // 订单状态 0未支付，1已经支付
                orderInfo.setOrderInfoStatus(0);
                // 商品名字
                orderInfo.setTicketDetailsInfo(ticketDetails.getTicketDetailsInfo());
                // TODO 票品时间 应该界面传递 30天之后
                orderInfo.setTicketTime(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 30));
                // 演出场馆
                orderInfo.setTicketAddressVenue(ticketDetails.getTicketAddressVenue());
                // 多个座位的坐标，如：2排15号,2排16号
                orderInfo.setSeats(builder.toString());
                // 多个订单的id
                orderInfo.setSeatsId(seatsId.toString());
                // 订单编号，是当前时间的毫秒值
                orderInfo.setOrderNumber(System.currentTimeMillis());
                // 订单的电子票地址
                // 此时没有付款，没有电子票信息
                orderInfo.setOrderInfoTicketEleImgUrl(null);
                // 更新数据到数据库
                orderInfoService.insert(orderInfo);
                // 更新订单和用户进行关联
                UserInfoOrderInfoMiddle infoMiddle = new UserInfoOrderInfoMiddle();
                Long userId = (Long) request.getAttribute("user_id");
                infoMiddle.setUserInfoMiddleId(userId);
                Long orderInfoId = orderInfo.getOrderInfoId();
                infoMiddle.setOrderInfoMiddleId(orderInfoId);
                infoMiddle.setCreateTime(new Date());
                infoMiddle.setUpdateTime(new Date());
                userInfoOrderInfoMiddleService.insert(infoMiddle);
                // 把订单存放在集合中
                returnData.add(orderInfo);
                // 把座位的id放到Redis中，下面生成订单，同时应该把座位 id 也存储进去，并且设置时间
                // 此处 key 为订单id ,值为座位编号
                redisUtils.set(String.valueOf(orderInfoId), seatsList, 17, TimeUnit.MINUTES);
                // 放置到定时任务队列中去
                TaskBase taskBase = new TaskBase();
                taskBase.setIdentifier(String.valueOf(orderInfoId));
                DelayTask delayTask = new DelayTask(taskBase, 1000 * 60 * 15);
                delayQueueManager.put(delayTask);
                log.info("UserConfirmOrderServiceImpl.confirmOrder - 加入订单到延时队列中去");
            }
            return JsonData.builderSuccess(returnData, "您的订单已经生成，座位已经锁定");
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
            log.error(e.getLocalizedMessage());
            return JsonData.builderError("系统异常！等到超时！");
        }
    }

    @Override
    public JsonData getBuyPageData(Long orderInfoId, Long userInfoId) {
        // 查询票的信息
        OrderInfo orderInfo = orderInfoService.queryById(orderInfoId);
        // 查询常用购票人 根据用户的id查询
        List<UserBuyerTicketDTO> ticketDTOS = userBuyerTicketService.queryUserBuyerTicketDTOByUserInfoId(userInfoId);
        ArrayList<Object> list = new ArrayList<>();
        list.add(orderInfo);
        list.add(ticketDTOS);
        return JsonData.builderSuccess(list);
    }

    /**
     * 数据处理
     *
     * @param list        购票人数组
     * @param orderInfoId 订单id
     * @return 生成票和购票人的id
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public JsonData getBuyPageDataAfterConfirm(String[] list, Long orderInfoId, Long ticketId) {
        if (null == list || list.length == 0 || null == orderInfoId || null == ticketId) {
            return JsonData.builderError("处理失败，数据异常");
        }

        // 根据 orderInfoId 和 ticketId 查询数据，是否已经存在，存在不能重复添加
        OrderInfoTicketInfoMiddle middle = orderInfoTicketInfoMiddleService.queryByOrderInfoIdAndTicketId(orderInfoId, ticketId);
        if (null != middle) {
            return JsonData.builderError("已经选过购票人，请去个人中心查看");
        }

        // 处理订单
        int length = list.length;
        StringBuilder builder = new StringBuilder(length * 2 - 1);
        for (int i = 0; i < list.length; i++) {
            if (i == length - 1) {
                builder.append(list[i]);
            } else {
                builder.append(list[i]).append(",");
            }
        }
        try {
            // 购票人id
            String buyers = builder.toString();
            // 创建订单和票信息的关联表对象 用来存储订单的购票人信息
            OrderInfoTicketInfoMiddle infoMiddle = new OrderInfoTicketInfoMiddle();
            // 票信息id
            infoMiddle.setTicketInfoMiddleId(ticketId);
            // 订单id
            infoMiddle.setOrderInfoMiddleId(orderInfoId);
            // 购票人列表
            infoMiddle.setBuyers(buyers);
            // 设置时间
            infoMiddle.setCreateTime(new Date());
            infoMiddle.setUpdateTime(new Date());
            orderInfoTicketInfoMiddleService.insert(infoMiddle);
            return JsonData.builderSuccess();
        } catch (Exception e) {
            e.printStackTrace();
            return JsonData.builderError("数据处理异常");
        }
    }
}
